<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.8"/>
<title>libnetconf: Transaction API (transAPI)</title>
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<link href="../../navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../resize.js"></script>
<script type="text/javascript" src="../../navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
  $(window).load(resizeHeight);
</script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/javascript">
  $(document).ready(function() { searchBox.OnSelectItem(0); });
</script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../libnetconf-logo.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">libnetconf
   &#160;<span id="projectnumber">0.9.0-110_trunk</span>
   </div>
   <div id="projectbrief">NETCONF Library</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.8 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
  <div id="navrow1" class="tabs">
    <ul class="tablist">
      <li><a href="../../index.html"><span>Main&#160;Page</span></a></li>
      <li class="current"><a href="../../pages.html"><span>Related&#160;Pages</span></a></li>
      <li><a href="../../modules.html"><span>Modules</span></a></li>
      <li><a href="../../annotated.html"><span>Data&#160;Structures</span></a></li>
      <li><a href="../../files.html"><span>Files</span></a></li>
      <li>
        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="../../search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="Search" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="../../search/close.png" alt=""/></a>
          </span>
        </div>
      </li>
    </ul>
  </div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('d9/d25/transapi.html','../../');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>Data Structures</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>Files</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark">&#160;</span>Functions</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark">&#160;</span>Variables</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(5)"><span class="SelectionMark">&#160;</span>Typedefs</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(6)"><span class="SelectionMark">&#160;</span>Enumerations</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(7)"><span class="SelectionMark">&#160;</span>Enumerator</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(8)"><span class="SelectionMark">&#160;</span>Macros</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(9)"><span class="SelectionMark">&#160;</span>Modules</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(10)"><span class="SelectionMark">&#160;</span>Pages</a></div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">Transaction API (transAPI) </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>Libnetconf transAPI is a framework designed to save developers time and let them focus on configuring and managing their device instead of fighting with the NETCONF protocol.</p>
<p>It allows a developer to choose parts of a configuration that can be easily configured as a single block. Based on a list of so called 'sensitive paths' the generator creates C code containing a single callback function for every 'sensitive path'. Whenever something changes in the configuration file, the appropriate callback function is called and it is supposed to reflect configuration changes in the actual device behavior.</p>
<p>Additionaly, transAPI provides an opportunity to implement behavior of NETCONF RPC operation defined in the data model. In case <em>lnctool(1)</em> finds an RPC definition inside the provided data model, it generates callbacks for it too. Whenever a server calls <a class="el" href="../../db/d67/group__store.html#ga6e6e979bd82e50913c82b4dc37cb8759" title="Perform the requested RPC operation on the all datastores controlled by the libnetconf (created by nc...">ncds_apply_rpc2all()</a> with RPC message containing such defined RPC operation, libnetconf uses callback function implemented in the module.</p>
<h1><a class="anchor" id="understanding-parameters"></a>
Understanding callback parameters</h1>
<p>Every transapi callback function has fixed set of parameters. Function header looks like this:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> callback_path_into_configuration_xml(<span class="keywordtype">void</span> **data, <a class="code" href="../../d8/d55/group__transapi.html#ga10d59d84527f735d2781dbbb629a4488">XMLDIFF_OP</a> op, xmlNodePtr old_node, xmlNodePtr new_node, <span class="keyword">struct</span> nc_err **error)</div>
</div><!-- fragment --><h2><a class="anchor" id="data"></a>
void **data</h2>
<p>This parameter was added to provide a way to share any data between callbacks. libnetconf never change (or even access) content of this parameter. Initialy content of 'data' is NULL. transapi module may use 'data' as it like but is also fully responsible for correct memory handling and freeing of no longer needed memory referenced by 'data'.</p>
<h2><a class="anchor" id="op"></a>
XMLDIFF_OP op</h2>
<p>Parameter op indicates what event(s) was occured on node. All events are bitwise ored. To test if certaint event occured on node use bitwise and (&amp;).</p>
<ul>
<li>Node can be added or removed.<ul>
<li>XMLDIFF_ADD = Node was added.</li>
<li>XMLDIFF_REM = Node was removed.</li>
</ul>
</li>
<li>Nodes of type leaf can be changed.<ul>
<li>XMLDIFF_MOD = Node content was changed.</li>
</ul>
</li>
<li>Container nodes are informed about events occured on descendants. It can be distinguished whether the event was processed or not.<ul>
<li>XMLDIFF_MOD = Some of node children was changed and there is not callback specified for it.</li>
<li>XMLDIFF_CHAIN = Some of node children was changed and associated callback was called.</li>
</ul>
</li>
<li>Additionaly, user-ordered lists and leaf-lists are notified when change in order occurs.<ul>
<li>XMLDIFF_SIBLING = Change in order. Some of siblings was added, removed or changed place.</li>
<li>XMLDIFF_REORDER = Undrelying user-ordered list has changed order.</li>
</ul>
</li>
</ul>
<h3><a class="anchor" id="combinations"></a>
Valid combinations of events</h3>
<ul>
<li>XMLDIFF_ADD and XMLDIFF_REM can never be specified simutaneously.</li>
<li>other restrictions depend on node type:<ul>
<li>Leaf: exactly one of XMLDIFF_ADD, XMLDIFF_REM, XMLDIFF_MOD</li>
<li>Container: at least one of XMLDIFF_ADD, XMLDIFF_REM, XMLDIFF_MOD, XMLDIFF_CHAIN and posibly XMLDIFF_REORDER when node holds user-ordered list</li>
<li>List (system-ordered): at least one of XMLDIFF_ADD, XMLDIFF_REM, XMLDIFF_MOD, XMLDIFF_CHAIN and posibly XMLDIFF_REORDER when node holds user-ordered list</li>
<li>List (user-ordered): at least one of XMLDIFF_ADD, XMLDIFF_REM, XMLDIFF_MOD, XMLDIFF_CHAIN, XMLDIFF_SIBLING and posibly XMLDIFF_REORDER when node holds user-ordered list</li>
<li>Leaf-list (system-ordered): exactly one of XMLDIFF_ADD, XMLDIFF_REM</li>
<li>Leaf-list (user-ordered): at least one of XMLDIFF_ADD, XMLDIFF_REM, XMLDIFF_SIBLING</li>
</ul>
</li>
</ul>
<p>Ex.: Leaf processing </p><div class="fragment"><div class="line"><span class="keywordtype">int</span> callback_some_leaf(<span class="keywordtype">void</span> **data, <a class="code" href="../../d8/d55/group__transapi.html#ga10d59d84527f735d2781dbbb629a4488">XMLDIFF_OP</a> op, xmlNodePtr old_node, xmlNodePtr new_node, <span class="keyword">struct</span> nc_err **error) {</div>
<div class="line">  <span class="keywordflow">if</span> (op &amp; <a class="code" href="../../d8/d55/group__transapi.html#gga10d59d84527f735d2781dbbb629a4488a27c20d1fff6c4a35673bea8c6bbe23c4">XMLDIFF_MOD</a>) {</div>
<div class="line">    <span class="comment">// change configured value</span></div>
<div class="line">  } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (op &amp; <a class="code" href="../../d8/d55/group__transapi.html#gga10d59d84527f735d2781dbbb629a4488a149cdeec9d87bdbb700861f773759129">XMLDIFF_REM</a>) {</div>
<div class="line">    <span class="comment">// leaf removed (disable service, close port, ...)</span></div>
<div class="line">  } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (op &amp; <a class="code" href="../../d8/d55/group__transapi.html#gga10d59d84527f735d2781dbbb629a4488adc0f4fc8354a1e293db5efd4f8e6f0b1">XMLDIFF_ADD</a>) {</div>
<div class="line">    <span class="comment">// leaf added (enable service, open port, ...)</span></div>
<div class="line">  } <span class="keywordflow">else</span> {</div>
<div class="line">    *error = <a class="code" href="../../d3/d35/group__gen_a_p_i.html#ga057524ba5256c428b6bf88710f000e0c">nc_err_new</a>(<a class="code" href="../../da/d41/error_8h.html#a170ed93037b65394a05e074400848eb2ae9d2e7a938b0fb4583b961a7079aabe3">NC_ERR_OP_FAILED</a>);</div>
<div class="line">    <a class="code" href="../../d3/d35/group__gen_a_p_i.html#gab28d881eeebd79d485391ae1ffc97299">nc_err_set</a>(error, <a class="code" href="../../d3/d7a/netconf_8h.html#a39c5f77f5cf9108a27e7a65f3b2ba73da1695230cad67458870f4cf93a2d530a5">NC_ERR_PARAM_MSG</a>, <span class="stringliteral">&quot;Invalid event for leaf node /some/leaf.&quot;</span>);</div>
<div class="line">    <span class="keywordflow">return</span>(EXIT_FAILURE);</div>
<div class="line">  }</div>
<div class="line">  <span class="keywordflow">return</span>(EXIT_SUCCESS);</div>
<div class="line">}</div>
</div><!-- fragment --><h2><a class="anchor" id="node"></a>
xmlNodePtr old_node &amp; new_node</h2>
<p>Pointer to a particular node instance in either the old or new configuration document, in which the event was detected. When the node was removed, new node is not set and when the node was deleted, old node is not set. It is safe to traverse the whole document using these pointers, but should be used only when necessary, since transAPI itself does this for you.</p>
<dl class="section note"><dt>Note</dt><dd>It is safe to traverse these nodes, but any modification will normally be lost. If you need to change some nodes, you can do so, but only in the new_node subtree (not available on XMLDIFF_REM). Then, for these changes to be written to the datastore, change 'config_modified' to 1. This variable is generated into every module.</dd></dl>
<h2><a class="anchor" id="error"></a>
strict nc_err **error</h2>
<p>libnetconf's error structure. May (and should) be used to specify error when it occurs and callback returns EXIT_FAILURE. Error description is forwarded to client.</p>
<h1><a class="anchor" id="transAPI-history"></a>
History of the transAPI versions</h1>
<p>Each transAPI module source code is generated with the <code>transapi_version</code> variable set to the transAPI version supported by the code generator (<em>lnctool(1)</em>). libnetconf requires exactly the same transAPI version in the modules as it supports itself. However, some of the transAPI versions are kind of backward compatible, so it is possible to simply change the value of the <code>transapi_version</code> variable in the module source code. In that case no additional changes to the transAPI module source code are required.</p>
<p>Here is the list of transAPI versions with notes to the changed things and to the backward compatibility.</p>
<ul>
<li><em>version 1</em><ul>
<li>Initial reversion.</li>
</ul>
</li>
<li><em>version 2</em><ul>
<li>Allow callbacks to modify configuration data. This action is announced by the callback via the <code>config_modified</code> variable.</li>
<li>Changes prototype of the transAPI callbacks. It allows to return NETCONF error description structure from the callbacks.</li>
<li>Backward incompatible.</li>
</ul>
</li>
<li><em>version 3</em><ul>
<li>Changes prototype of the <code>transapi_init()</code> function. It allows the module can announce to libnetconf the initial configuration of the device when the module is loaded.</li>
<li>Changes prototype of the transAPI callbacks. The configuration data are passed to the callbacks only as the libxml2 structures. Callbacks variant passing configuration data as strings are no longer available.</li>
<li>Backward incompatible.</li>
</ul>
</li>
<li><em>version 4</em><ul>
<li>Callback order - the module can change the order of executing callbacks from the default 'from leafs to root<code>to 'from root to leafs</code>. This is done via the <code>callbacks_order</code> variable. If the variable is not defined (such as in a transAPI v3 module), the default callback order is used.</li>
<li>Backward compatible.</li>
</ul>
</li>
<li><em>version 5</em><ul>
<li>Adds support for monitoring external files.</li>
<li>Backward compatible.</li>
</ul>
</li>
<li><em>version 6</em><ul>
<li>Every data callback now receives the corresponding node from both the old configuration and the new configuration. This holds for every operation except XMLDIFF_ADD (the old node is NULL) and XMLDIFF_REM (the new node is NULL).</li>
<li>Every RPC callback now receives a list of all the arguments and it is up to developers to parse them themselves. To help with this, a simple function get_rpc_node() is included in a transAPI module code.</li>
<li>Backward incompatible.</li>
</ul>
</li>
</ul>
<h1><a class="anchor" id="transapiTutorial"></a>
transAPI Tutorial</h1>
<p>On this page we will show how to write a simple module for controlling an example Turing machine. The full implementation can be found in the <a href="https://code.google.com/p/netopeer">Netopeer project</a>. </p><dl class="section note"><dt>Note</dt><dd>To install libnetconf follow the instructions on the <a class="el" href="../../d9/d87/install.html">Compilation and Installation</a> page.</dd></dl>
<h2><a class="anchor" id="transapiTutorial-prepare"></a>
Preparations</h2>
<p>In this example we will work with the data model of a Turing machine provided by the Pyang project (<a href="https://code.google.com/p/pyang/source/browse/trunk/doc/tutorial/examples/turing-machine.yang">https://code.google.com/p/pyang/source/browse/trunk/doc/tutorial/examples/turing-machine.yang</a>).</p>
<p>First, we need to identify important parts of the configuration data. Since the turing-machine data model describes only one configurable subtree, we have an easy choice. So, we can create the 'paths_file' file containing the specification of our chosen element and mapping prefixes with URIs for any used namespace.</p>
<p>Our file may look like this (irrespective of order): </p><div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;tm=http://example.net/turing-machine</div>
<div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;/tm:turing-machine/tm:transition-function/tm:delta</div>
</div><!-- fragment --><h2><a class="anchor" id="transapiTutorial-generating"></a>
Generating code</h2>
<ol type="1">
<li>Create a new directory for the turing-machine module and move the data model and the path file into it: <div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;$ mkdir turing-machine &amp;&amp; cd turing-machine/</div>
<div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;$ mv ../turing-machine.yang ../paths_file .</div>
</div><!-- fragment --></li>
<li>Run <em>lnctool(1)</em> for transapi: <div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;$ lnctool --model ./turing-machine.yang transapi --paths ./paths_file</div>
</div><!-- fragment --></li>
</ol>
<p>Besides the generated source code of our transAPI module and GNU Build System files (Makefile.in, configure.in,...), <em>lnctool(1)</em> also generates YIN format of the data model and validators accepted by the libnetconf's <a class="el" href="../../d8/d55/group__transapi.html#ga80e69b4cada8c35e5e358287e8af3d85" title="Create new datastore structure with transaction API support. ">ncds_new_transapi()</a> and <a class="el" href="../../db/d67/group__store.html#ga4777c16043f5856c5a65bcd20b5ecc31" title="Set validators (or disable validation) on the specified datastore. ">ncds_set_validation()</a> functions:</p><ul>
<li>*.yin - YIN format of the data model</li>
<li>*.rng - RelagNG schema for syntax validation</li>
<li>*-schematron.xsl - Schematron XSL stylesheet for semantics validation</li>
</ul>
<p>The data model can define various <code>feature</code>s and use them via the <code>if-feature</code> clauses. By default, all features are enabled for the validators. If you plan to to implement only a specific set (or none) of features, specify it to using the <code>--feature</code>` option (that can be used multiple times). The value has the following syntax:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;--feature module_name:feature_to_enable</div>
</div><!-- fragment --><p>If you want to disable all features of the module, use the following syntax:</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;--feature module_name:</div>
</div><!-- fragment --><h2><a class="anchor" id="transapiTutorial-augmenting"></a>
Augmenting module</h2>
<p>When you are adding a model augmenting the original model, you have generally 2 ways of doing so: <br />
</p><ol type="1">
<li>Create a new transAPI module implementing the original model with any augments, basically treating it as a single model. This way you receive a standalone transAPI module that will make the original module obsolete. <em>lnctool(1)</em> command: <div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;$ lnctool --model &lt;original_model&gt; --augment-model &lt;augment_model&gt; transapi --path &lt;paths_for_original_and_augment_model&gt;</div>
</div><!-- fragment --> <br />
</li>
<li>Create a new transAPI module implementing only the augmented parts. This way you receive an additional module that will be used together with the original module, which does not need to be modified in any way. <em>lnctool(1)</em> command: <div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;$ lnctool --model &lt;augment_model&gt; transapi --path &lt;paths_for_augment_model&gt;</div>
</div><!-- fragment --></li>
</ol>
<p><br />
However, the case when a model is augmenting an RPC in the original model is special and ONLY the first way of augmenting a module can and MUST be used.</p>
<h2><a class="anchor" id="transapiTutorial-coding"></a>
Filling up functionality</h2>
<p>Here we show a turing-machine simulating module. The full implementation can be found in the <a href="https://code.google.com/p/netopeer">Netopeer project</a> repository (transAPI/turing/turing-machine.c). The example functions and all the code is simplified and NOT thread-safe.</p>
<ol type="1">
<li>Open 'turing-machine.c' file with your favorite editor:<br />
<br />
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;$ vim turing-machine.c</div>
</div><!-- fragment --> <br />
</li>
<li>Add global variables and auxiliary functions. This is completely up to you, libnetconf does not work with this anyway. For full explanation of this code look into the referenced working example. It should be called to run the Turing machine, once set up, but some parts were omitted.<br />
<br />
<div class="fragment"><div class="line"><span class="keyword">static</span> tape_symbol *tm_head = NULL;</div>
<div class="line"><span class="keyword">static</span> tape_symbol *tm_tape = NULL;</div>
<div class="line"><span class="keyword">static</span> cell_index tm_tape_len = 0;</div>
<div class="line"><span class="keyword">static</span> state_index tm_state = 0;</div>
<div class="line"><span class="keyword">static</span> <span class="keyword">struct </span>delta_rule *tm_delta = NULL;</div>
<div class="line"></div>
<div class="line"><span class="keyword">static</span> <span class="keywordtype">void</span>* tm_run(<span class="keywordtype">void</span> *arg) {</div>
<div class="line">        <span class="keywordtype">int</span> changed = 1;</div>
<div class="line">        <span class="keyword">struct </span>delta_rule *rule = NULL;</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">while</span>(changed) {</div>
<div class="line">                changed = 0;</div>
<div class="line"></div>
<div class="line">                <span class="keywordflow">if</span> (tm_head &lt; tm_tape || (tm_head - tm_tape) &gt;= tm_tape_len) {</div>
<div class="line">                        <span class="keywordflow">break</span>;</div>
<div class="line">                }</div>
<div class="line"></div>
<div class="line">                <span class="keywordflow">for</span> (rule = tm_delta; rule != NULL; rule = rule-&gt;next) {</div>
<div class="line">                        <span class="keywordflow">if</span> (rule-&gt;in_state == tm_state &amp;&amp; rule-&gt;in_symbol == tm_head[0]) {</div>
<div class="line">                                <span class="keywordflow">if</span> (rule-&gt;out_state != 0xffff) {</div>
<div class="line">                                        tm_state = rule-&gt;out_state;</div>
<div class="line">                                }</div>
<div class="line">                                tm_head[0] = rule-&gt;out_symbol;</div>
<div class="line">                                tm_head = tm_head + rule-&gt;head_move;</div>
<div class="line"></div>
<div class="line">                                changed = 1;</div>
<div class="line"></div>
<div class="line">                                usleep(100);</div>
<div class="line">                                <span class="keywordflow">break</span>;</div>
<div class="line">                        }</div>
<div class="line">                }</div>
<div class="line">        }</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">return</span> (NULL);</div>
<div class="line">}</div>
</div><!-- fragment --> <br />
</li>
<li><p class="startli">Complete the 'transapi_init()' function with actions that will be run right after the module loads and before any other function in the module is called.<br />
<br />
The 'running' parameter can optionally return the current configuration state of the device as the 'transapi_init()' detects it. The configuration must correspond with the device data model and it is supposed to contain only the configuration data (defined with 'config true`). The returned data are then compared with the startup configuration and only the diverging values are set according to the startup content using the appropriate transAPI callback functions.<br />
<br />
We ignore it in our example - the Turing machine does not have any configuration that could be read from (depend on the state of) the system.</p>
<dl class="section note"><dt>Note</dt><dd>After returning from 'transapi_init()' it is assumed that the current running configuration reflects the actual state of the controlled device. For instance, if the model includes some default values and the running configuration is empty, libnetconf assumes that the device is in this default state as defined in the model. If not, then you should apply the default configuration on the device in 'transapi_init()'.</dd></dl>
<p><br />
</p><div class="fragment"><div class="line"><span class="keywordtype">int</span> transapi_init(xmlDocPtr *running) {</div>
<div class="line">    <span class="keywordflow">return</span> EXIT_SUCCESS;</div>
<div class="line">}</div>
</div><!-- fragment --><p> <br />
</p>
</li>
<li>Locate the 'transapi_close()' function and fill it with actions that will be run just before the module unloads. No other function of the transAPI module is called after the 'transapi_close()'. We free up all the temporary variables used to store the current state of the machine.<br />
<br />
<div class="fragment"><div class="line"><span class="keywordtype">void</span> transapi_close(<span class="keywordtype">void</span>) {</div>
<div class="line">        <span class="keyword">struct </span>delta_rule *rule;</div>
<div class="line"></div>
<div class="line">        free(tm_tape);</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">for</span> (rule = tm_delta; rule != NULL; rule = tm_delta) {</div>
<div class="line">                tm_delta = rule-&gt;next;</div>
<div class="line">                free_delta_rule(rule);</div>
<div class="line">        }</div>
<div class="line">}</div>
</div><!-- fragment --> <br />
</li>
<li>Fill 'get_state_data()' function. This function returns (only!) the state data (defined with 'config false').<br />
<br />
<div class="fragment"><div class="line"><span class="keywordtype">char</span> * get_state_data(<span class="keywordtype">char</span> * model, <span class="keywordtype">char</span> * running, <span class="keyword">struct</span> nc_err **err) {</div>
<div class="line">    <span class="keywordflow">return</span> strdup(<span class="stringliteral">&quot;&lt;?xml version=&quot;</span>1.0<span class="stringliteral">&quot;?&gt;&lt;turing-machine xmlns=&quot;</span>http:<span class="comment">//example.net/turing-machine&quot;&gt; ... &lt;/turing-machine&gt;&quot;);</span></div>
<div class="line">}</div>
</div><!-- fragment --> <br />
</li>
<li>Complete the configuration callbacks (they have the <code>callback_</code> prefix). The 'op' parameter can be used to determine operation which was done with the node. Parameter 'old_node' holds a copy of node before the change and 'new_node' after the change. More detailed information about the callback parameters can be found above in the <a class="el" href="../../d9/d25/transapi.html#understanding-parameters">Understanding callback parameters</a> section.<br />
<br />
In this code, we treat modification as a removal and an immediate addition to limit branching and simplifiy the code. <div class="fragment"><div class="line"><span class="keywordtype">int</span> callback_tm_turing_machine_tm_transition_function_tm_delta(<span class="keywordtype">void</span> **data, <a class="code" href="../../d8/d55/group__transapi.html#ga10d59d84527f735d2781dbbb629a4488">XMLDIFF_OP</a> op, xmlNodePtr old_node, xmlNodePtr new_node, <span class="keyword">struct</span> nc_err **error) {</div>
<div class="line">        <span class="keywordtype">char</span> *content = NULL;</div>
<div class="line">        xmlNodePtr n1, n2;</div>
<div class="line">        <span class="keyword">struct </span>delta_rule *rule = NULL;</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">if</span> (op &amp; XMLDIFF_MOD) {</div>
<div class="line">                op = op | (XMLDIFF_REM &amp; <a class="code" href="../../d8/d55/group__transapi.html#gga10d59d84527f735d2781dbbb629a4488adc0f4fc8354a1e293db5efd4f8e6f0b1">XMLDIFF_ADD</a>);</div>
<div class="line">        }</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">if</span> (op &amp; XMLDIFF_REM) {</div>
<div class="line">                <span class="comment">//remove the rule from the internal list</span></div>
<div class="line">        }</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">if</span> (op &amp; XMLDIFF_ADD) {</div>
<div class="line">                <span class="comment">//parse the children of new_node and add the new rule to the list</span></div>
<div class="line">        }</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">return</span> EXIT_SUCCESS;</div>
<div class="line">}</div>
</div><!-- fragment --> <br />
</li>
<li>Fill the RPC message callback functions with the code that will be run when an RPC message with the defined operation arrives.<br />
<br />
The RPC defines an optional parameter 'tape-content', so we use it if specified, otherwise use the default value.<br />
<br />
<div class="fragment"><div class="line"><a class="code" href="../../d0/de2/group__reply.html#ga40338a1274759a932a7c2c7b8ed0121d">nc_reply</a> *rpc_initialize(xmlNodePtr input) {</div>
<div class="line">        xmlNodePtr tape_content = get_rpc_node(<span class="stringliteral">&quot;tape-content&quot;</span>, input);</div>
<div class="line">        <span class="keyword">struct </span>nc_err* e = NULL;</div>
<div class="line"></div>
<div class="line">        free(tm_tape);</div>
<div class="line"></div>
<div class="line">        tm_state = 0;</div>
<div class="line">        tm_tape = tm_head = (<span class="keywordtype">char</span>*)xmlNodeGetContent(tape_content);</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">if</span> (tm_tape == NULL) {</div>
<div class="line">                tm_tape = tm_head = strdup(<span class="stringliteral">&quot;&quot;</span>);</div>
<div class="line">        }</div>
<div class="line"></div>
<div class="line">        tm_tape_len = strlen(tm_tape) + 1;</div>
<div class="line">        pthread_mutex_unlock(&amp;tm_run_lock);</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">return</span> <a class="code" href="../../d0/de2/group__reply.html#ga047f565bb3671ec4016fef5461e8f67e">nc_reply_ok</a>();</div>
<div class="line">}</div>
</div><!-- fragment --> <br />
To run the machine, we create another thread and let it run in the background. There are no parameters, so we ignore the input.<br />
<br />
<div class="fragment"><div class="line"><a class="code" href="../../d0/de2/group__reply.html#ga40338a1274759a932a7c2c7b8ed0121d">nc_reply</a> *rpc_run(xmlNodePtr input) {</div>
<div class="line">        pthread_t tm_run_thread;</div>
<div class="line">        <span class="keyword">struct </span>nc_err *e;</div>
<div class="line">        <span class="keywordtype">char</span> *emsg = NULL;</div>
<div class="line">        <span class="keywordtype">int</span> r;</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">if</span> ((r = pthread_create(&amp;tm_run_thread, NULL, tm_run, NULL)) != 0) {</div>
<div class="line">                e = <a class="code" href="../../d3/d35/group__gen_a_p_i.html#ga057524ba5256c428b6bf88710f000e0c">nc_err_new</a>(<a class="code" href="../../da/d41/error_8h.html#a170ed93037b65394a05e074400848eb2ae9d2e7a938b0fb4583b961a7079aabe3">NC_ERR_OP_FAILED</a>);</div>
<div class="line">                asprintf(&amp;emsg, <span class="stringliteral">&quot;Unable to start turing machine thread (%s)&quot;</span>, strerror(r));</div>
<div class="line">                <a class="code" href="../../d3/d35/group__gen_a_p_i.html#gab28d881eeebd79d485391ae1ffc97299">nc_err_set</a>(e, <a class="code" href="../../d3/d7a/netconf_8h.html#a39c5f77f5cf9108a27e7a65f3b2ba73da1695230cad67458870f4cf93a2d530a5">NC_ERR_PARAM_MSG</a>, emsg);</div>
<div class="line">                free(emsg);</div>
<div class="line">                <span class="keywordflow">return</span> <a class="code" href="../../d0/de2/group__reply.html#ga12fd89263289491b84398279e0e449fd">nc_reply_error</a>(e);</div>
<div class="line">        }</div>
<div class="line"></div>
<div class="line">        pthread_detach(tm_run_thread);</div>
<div class="line"></div>
<div class="line">        <span class="keywordflow">return</span> <a class="code" href="../../d0/de2/group__reply.html#ga047f565bb3671ec4016fef5461e8f67e">nc_reply_ok</a>();</div>
<div class="line">}</div>
</div><!-- fragment --> <br />
</li>
<li>Optionally, you can set monitoring for some external configuration file.<br />
<br />
Let's say, that our Turing machine has a textual configuration located in the <code>/etc/turing.conf</code> file. libnetconf can monitor this file for modification and whenever an external application changes content of the file, the specified callback is executed. It's up to the callback function to open the file for reading and get the current configuration data.<br />
<br />
<div class="fragment"><div class="line"><span class="keywordtype">int</span> example_callback(<span class="keyword">const</span> <span class="keywordtype">char</span> *filepath, xmlDocPtr *running, <span class="keywordtype">int</span>* execflag) {</div>
<div class="line">    <span class="comment">// do nothing</span></div>
<div class="line">    *running = NULL;</div>
<div class="line">    *execflag = 0;</div>
<div class="line"></div>
<div class="line">    <span class="keywordflow">return</span> EXIT_SUCCESS;</div>
<div class="line">}</div>
<div class="line"></div>
<div class="line"><span class="keyword">struct </span><a class="code" href="../../de/df8/structtransapi__file__callbacks.html">transapi_file_callbacks</a> file_clbks = {</div>
<div class="line">    .<a class="code" href="../../de/df8/structtransapi__file__callbacks.html#a853d73f0f495147dba4842e9f860d1f0">callbacks_count</a> = 1,</div>
<div class="line">    .callbacks = {{.path = <span class="stringliteral">&quot;/etc/turing.conf&quot;</span>, .func = example_callback}}</div>
<div class="line">};</div>
</div><!-- fragment --> <br />
Here is the description of the callback function parameters:<br />
<ul>
<li><b>const char *filepath</b> - input parameter providing the path to the changed file</li>
<li><b>xmlDocPtr *edit_config</b> - output parameter to return content for the <code>edit-config</code> operation to change the content of the NETCONF running datastore.</li>
<li><b>int *exec</b> - output parameter to set if the performed changes should cause execution of the regular transAPI callbacks. If set to <code>0</code>, the changes are only reflected in the running configuration datastore, but no transAPI callback is executed.<br />
<br />
</li>
</ul>
</li>
<li>Done</li>
</ol>
<h2><a class="anchor" id="transapiTutorial-compiling"></a>
Compiling module</h2>
<p>Following sequence of commands will produce the shared library 'turing-machine.so' which may be loaded into libnetconf: </p><div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno">    1</span>&#160;$ autoreconf</div>
<div class="line"><a name="l00002"></a><span class="lineno">    2</span>&#160;$ ./configure</div>
<div class="line"><a name="l00003"></a><span class="lineno">    3</span>&#160;$ make</div>
</div><!-- fragment --><h2><a class="anchor" id="transapiTutorial-using"></a>
Integrating to a server</h2>
<p>In a server we use libnetconf's function <a class="el" href="../../d8/d55/group__transapi.html#ga80e69b4cada8c35e5e358287e8af3d85" title="Create new datastore structure with transaction API support. ">ncds_new_transapi()</a> instead of <a class="el" href="../../db/d67/group__store.html#ga69009c5985f9eec3a6920f98a6a1a5e6" title="Create a new datastore structure of the specified implementation type. ">ncds_new()</a> to create a transAPI-capable data store. Then, you do not need to process any data-writing (edit-config, copy-config, delete-config, lock, unlock), data-reading (get, get-config) or module data-model-defined RPC operations. All these operations are processed inside the <a class="el" href="../../db/d67/group__store.html#ga6e6e979bd82e50913c82b4dc37cb8759" title="Perform the requested RPC operation on the all datastores controlled by the libnetconf (created by nc...">ncds_apply_rpc2all()</a> function. </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="footer">Generated on Wed Apr 15 2015 14:51:21 for libnetconf by
    <a href="http://www.doxygen.org/index.html">
    <img class="footer" src="../../doxygen.png" alt="doxygen"/></a> 1.8.8 </li>
  </ul>
</div>
</body>
</html>
